<?php

// I need to type-cast data to send via json.  There are some mis-matches between mysql and php that need to be reconciled, so I need to figure those out.  But where should they happen??  Where should I reconcile it?  It's tough to know if I should break this out into multiple classes, or what.

// We need to assume the data has an arbitrary type BEFORE we put it in the table.  Can we type it right when we create the table?  Or will there be a case when we're modifying the data and its type somehow gets converted?

class TableColumn {
    private $name;
    private $type;
    private $cast_function;
    
    const TYPE_BOOL = 'boolean';
    const TYPE_INT = 'integer';
    const TYPE_FLOAT = 'double';
    const TYPE_STR = 'string';
    
    // Given text, will attempt to determine the data type.  
    // 'true' and 'false' are considered boolean
    public static function infer_type($string) {
        if (preg_match('/^\d+$/',$string)) return self::TYPE_INT;
        else if (preg_match('/^\d*\.\d+$/',$string)) return self::TYPE_FLOAT;
        else if (preg_match('/(true|false)/i',$string)) return self::TYPE_BOOL;
        else return self::TYPE_STR;
    }
    
    public function __construct($name,$type) {
        $this->name = $name;
        $this->type = $type;
        switch($type) {
            case self::TYPE_STR:
                $this->cast_function = function (&$var) { (string) $var; };
                break;
            case self::TYPE_INT:
                $this->cast_function = function (&$var) { (int) $var; };
                break;
            case self::TYPE_FLOAT:
                $this->cast_function = function (&$var) { (float) $var; };
                break;
            case self::TYPE_BOOL:
                $this->cast_function = function (&$var) { (bool) $var; };
                break;
            default:
                throw new Exception("Unknown type $type.");
                break;
        }
    }
    
    public function cast_type(&$var) { $this->cast_function($var); }
        
}

class Table {
    private $column_info;
    private $rows;
    
    private static function get_columns_typed ($typed_array) {
        $columns = array();
        foreach ($typed_array as $name=>$val) {
            $columns[] = new TableColumn($name,TableColumn::infer_type($val));
        }
        return $columns;
    }
        
    public static function create_table_from_array($array) {
        assert('is_array($array); //need an assoc array!');
        if (count($array)) $columns = self::get_columns_typed($array[0]);
        else throw new Exception("Empty array");
        print_r($columns);
        return new Table($columns,$array);
    }
    
    // first line must contain headers
    public static function create_table_from_delim($text,$row_delim,$col_delim,$strip_whitespace = false) {
        $text = rtrim($text," \r\n\0\x0B");
        $rows = explode($row_delim,$text);
        if ($numrows = count($rows)) {
            $notfirst = false;
            foreach ($rows as &$row) {
                $row = rtrim($row," \r\0\x0B");
                $row = explode($col_delim,$row);
            }
            unset($row);
            $header = array_slice($rows,0,1)[0];
            var_dump($header);
            $rows = $numrows > 1 ? array_slice($rows,1) : array();
            $column_info = array_combine($header,array_map('TableColumn::infer_type',$rows[0]));
            return new Table($column_info,$rows);
        }
    }
    
    // $rows should be a flat array.
    public function __construct($column_info,$rows) {
        $this->column_info = $column_info;
        $this->rows = $rows;
    }
    
    public function render_json() {
        $result = array();
        foreach ($this->column_info as $label=>
    }
        
}
        
        
    
?>